#include <fstream>
#include "roomblueprint.hpp"
#include "tilelayer.hpp"
#include "util.hpp"
#include "exception.hpp"
#include "fileutil.hpp"

namespace nmc
{
	RoomBlueprint::RoomBlueprint(int width, int height, const std::string& filename)
	{
		for (int i = 0; i < NUM_LAYERS; i++)
		{
			mLayers[i] = new TileLayer(width, height);
		}

		mFilename = filename;
	}

	RoomBlueprint::RoomBlueprint(const std::string& filename)
	{
		mFilename = filename;

        std::ifstream file(filename.c_str(), std::ios_base::in | std::ios_base::binary);

		if (!file.is_open() || !file.good())
		{
			file.close();
			throw NMC_EXCEPTION("Unable to open " + filename + " for reading.");
		}

        int width = readInt(file);
		int height = readInt(file);

		for (int i = 0; i < NUM_LAYERS; i++)
		{
			mLayers[i] = new TileLayer(width, height);
		}

		for (int i = 0; i < NUM_LAYERS; i++)
		{
			TileLayer *l = mLayers[i];

			for (int y = 0; y < getHeight(); y++)
			{
				for (int x = 0; x < getWidth(); x++)
				{
					int tile = readShort(file);
					l->setTile(x, y, tile);
				}
			}
		}

        file.close();
	}

	RoomBlueprint::~RoomBlueprint()
	{
		for (int i = 0; i < NUM_LAYERS; i++)
		{
			delete mLayers[i];
		}
	}

	void RoomBlueprint::save()
	{
		save(mFilename);
	}

	void RoomBlueprint::save(const std::string& filename)
	{
		mFilename = filename;
        std::ofstream file(filename.c_str(), std::ios_base::out | std::ios_base::binary);

		if (!file.is_open() || !file.good())
		{
			file.close();
			throw NMC_EXCEPTION("Unable to open " + filename + " for writing.");
		}

        writeInt(file, getWidth());
		writeInt(file, getHeight());

		for (int i = 0; i < NUM_LAYERS; i++)
		{
			TileLayer *l = mLayers[i];

			for (int y = 0; y < getHeight(); y++)
			{
				for (int x = 0; x < getWidth(); x++)
				{
					writeShort(file, (short)l->getTile(x, y));
				}
			}
		}

        file.close();
	}

	TileLayer *RoomBlueprint::getLayer(Layer layer)
	{
		return mLayers[layer];
	}

	void RoomBlueprint::resize(int width, int height)
	{
		for (int i = 0; i < NUM_LAYERS; i++)
		{
			TileLayer *newLayer = new TileLayer(width, height);

			int w = min(width, mLayers[i]->getWidth());
			int h = min(height, mLayers[i]->getHeight());

			for (int y = 0; y < h; y++)
			{
				for (int x = 0; x < w; x++)
				{				
					int tile = mLayers[i]->getTile(x, y);
					newLayer->setTile(x, y, tile);
				}
			}

			delete mLayers[i];
			mLayers[i] = newLayer;
		}
	}

	int RoomBlueprint::getWidth()
	{
		return mLayers[0]->getWidth();
	}

	int RoomBlueprint::getHeight()
	{
		return mLayers[0]->getHeight();
	}

	void RoomBlueprint::setWorldPosition(int x, int y)
	{
		mX = x;
		mY = y;
	}

	int RoomBlueprint::getWorldX()
	{
		return mX;
	}

	int RoomBlueprint::getWorldY()
	{
		return mY;
	}

	const std::string& RoomBlueprint::getFilename()
	{
		return mFilename;
	}

	BITMAP* RoomBlueprint::getMinimap()
	{
		return mMiniMap;
	}
}